<?php
/**
 * Project: firework-cms             >>  http://firework-cms.googlecode.com
 * Authors: YouniS Ben Salah  (-.-)  >>  http://younishd.kegtux.org
 *          Fabien Wang       (^.^)  >>  http://fabienwang.fr
 * License: See README and LICENSE in the top level directory
 */
// TODO: rename the constants in CRUD methods.
// like all RETRIEVE_ALL etc.
// CAPS LOCK FTW!!!!!!!!!!!!!!!1!!

/**
 * Module: Model [M]
 * Handles and provides the data needed by the webapp.
 */

require_once 'core/cl_config.php';
require_once 'core/cl_parser.php';

/**
 * Class: Model
 * generic model class.
 */
abstract class Model
{
    // CRUD methods
    abstract public function create( $data, $params );
    abstract public function retrieve( $data, $params );
    abstract public function update( $data, $params );
    abstract public function destroy( $data, $params );
}

/**
 * Class: DBConfModel
 * Extends Model ( DBConfModel IS_A Model )
 * Handles the information needed to connect to database.
 */
class DBConfModel extends Model
{
    // ctor
    public function __construct()
    {
        $this->parser = new ConfParser( 'config/dbconf.php' );
    }
    
    /**
     * Method: create()
     */
    public function create( $data, $params = NULL )
    {
        if ( isset($params['value'] ) ) {
            $this->parser->set( $data, $params['value'] );
        }
        else {
            throw new Exception( 'model failed to create '.$data.': check passed value.' );
        }
    }
    
    /**
     * Method: retrieve()
     */
    public function retrieve( $data, $params = NULL )
    {
        $dbconf_haystack = array(
            'engine',
            'host',
            'name',
            'user',
            'pwd' );
        if ( in_array( $data, $dbconf_haystack ) ) {
            return $this->parser->get($data);
        }
        else {
            throw new Exception( 'can\'t retrieve that shit. what the hell is a "'.$data.'"?');
        }
    }
    
    /**
     * Method: update()
     */
    public function update( $data, $params = NULL )
    {
        $this->create( $data, $params );
    }
    
    /**
     * Method: destroy()
     */
    public function destroy( $data, $params = NULL )
    {
        $this->parser->drop($data);
    }
    
    
    protected $parser;
}

/**
 * Class: AppConfModel
 * Extends Model ( AppConfModel IS_A Model )
 * Handles the settings data of the webapp.
 */
class AppConfModel extends Model
{
    // ctor
    public function __construct()
    {
        $this->parser = new ConfParser( 'config/appconf.php' );
    }
    
    /**
     * Method: create()
     */
    public function create( $data, $params = NULL )
    {
        if ( isset($params['value'] ) ) {
            $this->parser->set( $data, $params['value'] );
        }
        else {
            throw new Exception( 'model failed to create '.$data.': check passed value.' );
        }
    }
    
    /**
     * Method: retrieve()
     */
    public function retrieve( $data, $params = NULL )
    {
        switch ($data) {
            case 'title':
            if ( isset($params['suffix']) ) {
                $title = $this->parser->get('title').$params['suffix'];
                return $title;
            }
            else {
                throw new Exception( 'model failed to retrieve title: suffix not set.' );
            }
            break;
            
            default:
            $appconf_haystack = array(
                'screenname',
                'debug_lvl',
                'default_action',
                'errmsg_404',
                'nb_recent_posts',
                'write_log',
                'log_file' );
            if ( in_array( $data, $appconf_haystack ) ) {
                return $this->parser->get($data);
            }
            else {
                throw new Exception( 'can\'t retrieve that shit. what the hell is a "'.$data.'"?' );
            }
        }
    }
    
    /**
     * Method: update()
     */
    public function update( $data, $params = NULL )
    {
        $this->create( $data, $params );
    }
    
    /**
     * Method: destroy()
     */
    public function destroy( $data, $params = NULL )
    {
        $this->parser->drop($data);
    }
    
    
    protected $parser;
}

/**
 * Class: TemplateModel
 * Extends Model ( TemplateModel IS_A Model )
 * Handles the template data.
 */
class TemplateModel extends Model
{
    // ctor
    public function __construct()
    {
        $this->db = DB_CONFIG::CONNECT();
    }
    
    /**
     * Method: create()
     */
    public function create( $data, $params )
    {
        
    }
    
    /**
     * Method: retrieve()
     */
    public function retrieve( $data, $params = NULL )
    {
        switch($data) {
            case 'template':
            return $this->getDBAttrib( 'templconf', 'template' );
            
            default:
            throw new Exception( 'can\'t retrieve that shit. what the hell is a "'.$data.'"?');
        }
    }
    
    /**
     * Method: update()
     */
    public function update( $data, $params = NULL )
    {
        
    }
    
    /**
     * Method: destroy()
     */
    public function destroy( $data, $params = NULL )
    {
        
    }
    
    
    /**
     * Method: getDBAttrib()
     * returns value of an attribute from a table.
     */
    protected function getDBAttrib( $table, $attrib )
    {
        $query = $this->db->prepare( 'SELECT value FROM '.$table.' WHERE attrib = ?' );
        $query->execute( array( $attrib ) );
        $answer = $query->fetch();
        return $answer['value'];
    }
    
    protected $db;
}

/**
 * Class: BlogModel
 * Extends Model ( BlogModel IS_A Model )
 * Handles all blog related data.
 * ( posts, comments etc.. )
 * data is stored in db.
 */
class BlogModel extends Model
{
    // ctor
    public function __construct()
    {
        $this->db = DB_CONFIG::CONNECT();
    }
    
    // overloading CRUD methods
    /**
     * Method: create()
     */
    public function create( $data, $params = NULL )
    {
        // switch ( data )
        // case post: addPost( params[post] ... );
        // case comment: addComment( params[comment] );
        // ...
    }
    
    /**
     * Method: retrieve()
     * Returns requested data.
     * Accepts an array of parameters ( optional ).
     */
    public function retrieve( $data, $params = NULL )
    {
        switch ($data) {
            // post: needs id to be passed
            case 'post':
            if ( isset($params['id']) ) {
                return $this->getPosts( (int)$params['id'] );
            }
            else {
                throw new Exception( 'can\'t retrieve post. is it so difficult to pass valid id?' );
            }
            break;
            
            case 'post_title':
            if ( isset($params['id']) ) {
                return $this->getPostTitle( (int)$params['id'] );
            }
            else {
                throw new Exception( 'can\'t retrieve post. is it so difficult to pass valid id?' );
            }
            break;
                
            // posts: accepts limit else default
            case 'posts':
            if ( isset($params['limit']) ) {
                return $this->getPosts( 0, (int)$params['limit'] );
            }
            else {
                // last 10 ( default set in getPosts() )
                return $this->getPosts();
            }
            break;
                
            // comments: needs onpost param
            case 'comments':
            if ( isset($params['onpost']) ) {
                return $this->getComments( (int)$params['onpost'] );
            }
            else {
                throw new Exception( 'can\'t retrieve comments. verify onpost!');
            }                
            break;
            
            case 'nb_comments':
            if ( isset($params['onpost']) ) {
                return $this->getNbComments( (int)$params['onpost'] );
            }
            break;
                
            case 'nb_posts':
            return $this->getNbPosts();
            break;
                
            default:
            throw new Exception( 'can\'t retrieve that shit. what the hell is a "' . $data .'"?');
        }
    }
    
    /**
     * Method: update()
     */
    public function update( $data, $params = NULL )
    {
        // switch ( data )
        // case post: updatePost();
        // ...
    }
    
    /**
     * Method: destroy()
     */
    public function destroy( $data, $params = NULL )
    {
        // switch ( data )
        // case post: destroyPost();
        // case comment: destroyComment();
        // ...
    }
    
    
    /**
     * Method: getPosts()
     * Returns one or multiple posts from db
     * getPosts() : without parameters returns the last 10 posts
     * getPosts( $specific ) : returns the post which id is $specific
     * getPosts( 0, $limit ) : returns the last $limit posts
     */
    protected function getPosts( $specific = 0, $limit = 10 )
    {
        $specific = (int)$specific;
        $limit = (int)$limit;
        
        if ( $specific > 0 ) {
            $query = $this->db->prepare( 'SELECT * FROM posts WHERE postid = ?' );
            $query->execute( array($specific) );
            return $query;
        }
        else if ( $limit > 0 && $specific == 0 ) {
            $query = $this->db->prepare( 'SELECT * FROM posts ORDER BY creation_date DESC LIMIT 0, ?' );
            $query->bindValue( 1, $limit, PDO::PARAM_INT );
            $query->execute();
            return $query;
        }
        else {
            throw new Exception( 'failed in method "getPosts()" - arguments are nonsense. $specific='.$specific.'; $limit=' . $limit );
        }
    }
    
    /**
     * Method: getComments()
     * Returns a post's comments.
     */
    protected function getComments( $onpost )
    {
        $onpost = (int)$onpost;
        if ( $onpost > 0 ) {
            $query = $this->db->prepare( 'SELECT * FROM comments WHERE postid = ? ORDER BY creation_date DESC' );
            $query->execute( array($onpost) );
            return $query;
        }
        else {
            throw new Exception( 'failed in method "getComments()" - arguments are nonsense.' );
        }
    }
    
    /**
     * Method: getNbComments()
     * Returns number of comments on a post.
     */
    protected function getNbComments( $onpost )
    {
        $query = $this->db->prepare( 'SELECT COUNT(*) AS n FROM comments WHERE postid = ?' );
        $query->bindValue( 1, $onpost, PDO::PARAM_INT );
        $query->execute();
        $nb_comments = $query->fetch();
        return $nb_comments['n'];
    }
    
    /**
     * Method: getNbPosts()
     * Returns number of posts.
     */
    protected function getNbPosts()
    {
        $query = $this->db->query( 'SELECT COUNT(*) AS n FROM posts' );
        $nb_posts = $query->fetch();
        return $nb_posts['n'];
    }
    
    /**
     * Method: getPostTitle
     */
    protected function getPostTitle( $id )
    {
        if ( $id > 0 ) {
            $query = $this->db->prepare( 'SELECT title FROM posts WHERE postid = ?' );
            $query->execute( array($id) );
            $post_title = $query->fetch();
            return $post_title['title'];
        }
        else {
            return '';
        }
    }
    
    /**
     * Method: getDBAttrib()
     * returns value of an attribute from a table.
     * attrib=value
     */
    protected function getDBAttrib( $table, $attrib )
    {
        $query = $this->db->prepare( 'SELECT value FROM ' . $table . ' WHERE attrib = ?' );
        $query->execute( array( $attrib ) );
        $answer = $query->fetch();
        return $answer['value'];
    }
    
    // the database object
    protected $db;
}

/**
 * Class: MenuModel
 * Extends Model ( MenuModel IS_A Model )
 * Handles all menu related data.
 * ( links etc.. )
 * data is stored in db.
 */
class MenuModel extends Model
{
    // ctor
    public function __construct()
    {
        $this->db = DB_CONFIG::CONNECT();
    }
    
    /**
     * Method: create()
     */
    public function create( $data, $params = NULL )
    {
        
    }
    
    /**
     * Method: retrieve()
     */
    public function retrieve( $data, $params = NULL )
    {
        $query = $this->db->query( 'SELECT `text`, `link`, `target` FROM menus WHERE `menu` = \''.$data.'\' ORDER BY `order`' );
        if ($query == false) {
            throw new Exception( 'retrieve menu fail.' );
        }
        else return $query;
    }
    
    /**
     * Method: update()
     */
    public function update( $data, $params = NULL )
    {
        
    }
    
    /**
     * Method: destroy()
     */
    public function destroy( $data, $params = NULL )
    {
        
    }
        
    /**
     * Method: getDBAttrib()
     * returns value of an attribute from a table.
     */
    protected function getDBAttrib( $table, $attrib )
    {
        $query = $this->db->prepare( 'SELECT value FROM '.$table.' WHERE attrib = ?' );
        $query->execute( array( $attrib ) );
        $answer = $query->fetch();
        return $answer['value'];
    }
    
    protected $db;
}

/**
 * Class: PagesListModel
 * Extends Model ( PagesListModel IS_A Model )
 * Handles the list of pages.
 */
class PagesListModel extends Model
{
    // ctor
    public function __construct()
    {
        $this->parser = new ListConfParser( 'config/pages.php' );
    }
    
    /**
     * Method: create()
     */
    public function create( $data, $params = NULL )
    {
        // adding an element to the list.
        $this->parser->set( $data );
    }
    
    /**
     * Method: retrieve()
     */
    public function retrieve( $data, $params = NULL )
    {
        if ( $data == 'element' && isset($params['line']) ) {
            return $this->parser->get($params['line']);
        }
        else if ( $data == 'all' ) {
            return $this->parser->get();
        }
        else {
            throw new Exception( 'retrieve pages list fail. check data arg.' );
        }
    }
    
    /**
     * Method: update()
     */
    public function update( $data, $params = NULL )
    {
        $this->create($data);
    }
    
    /**
     * Method: destroy()
     */
    public function destroy( $data, $params = NULL )
    {
        $this->parser->drop($data);
    }
    
    
    protected $parser;
}
